<!DOCTYPE html>
<html>
<head>
    <title>Tetris</title>
    <style>
        canvas {
            border: 1px solid black;
        }
    </style>
</head>
<body>

<canvas id="canvas" width="300" height="600"></canvas>

<script>
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');

    // 游戏区域大小和每个方块大小
    const boardWidth = 10, boardHeight = 20;
    const blockSize = 30;

    // 定义所有可能的方块形状及其颜色
    const pieces = [
        { shape: [[1, 1, 1, 1]], color: '#00ffff' }, // I形方块
        { shape: [[1, 1, 0], [0, 1, 1]], color: '#ff00ff' }, // Z形方块
        { shape: [[0, 1], [0, 1], [1, 1]], color: '#ffa500' }, // L形方块
        { shape: [[1, 0], [1, 0], [1, 1]], color: '#0000ff' }, // J形方块
        { shape: [[0, 1, 1], [1, 1, 0]], color: '#00ff00' }, // S形方块
        { shape: [[1, 1], [1, 1]], color: '#ffff00' }, // O形方块
        { shape: [[0, 1], [1, 1], [0, 1]], color: '#ff0000' }, // T形方块
    ];

    // 初始化游戏区域数组
    let board = new Array(boardHeight);
    for (let i = 0; i < board.length; i++) {
        board[i] = new Array(boardWidth).fill(0);
    }

    // 当前下落的方块及其位置
    let currentPiece, pieceX, pieceY;

    // 初始化游戏状态
    init();

    function init() {
        newPiece();
        setInterval(update, 500); // 每500毫秒更新一次游戏界面
    }

    // 在随机位置生成一个新的方块
    function newPiece() {
        const randomIndex = Math.floor(Math.random() * pieces.length);
        currentPiece = pieces[randomIndex].shape;
        pieceX = Math.floor((boardWidth - currentPiece[0].length) / 2);
        pieceY = 0;
    }

    // 更新游戏状态
    function update() {
        moveDown();
        drawBoard();
    }

    // 将当前方块向下移动一格，如果不能移动则将方块放置到游戏区域中
    function moveDown() {
        if (canMove(currentPiece, pieceX, pieceY + 1)) {
            pieceY++;
        } else {
            placePiece();
            clearLines();
            newPiece();
        }
    }

    // 将当前方块放置到游戏区域中
    function placePiece() {
        for (let y = 0; y < currentPiece.length; y++) {
            for (let x = 0; x < currentPiece[y].length; x++) {
                if (currentPiece[y][x]) {
                    board[pieceY + y][pieceX + x] = currentPiece[y][x];
                }
            }
        }
    }

    // 检查并消除所有可以消除的行
    function clearLines() {
        for (let y = boardHeight - 1; y >= 0; y--) {
            if (board[y].every(block => block !== 0)) {
                board.splice(y, 1);
                board.unshift(new Array(boardWidth).fill(0));
                y++; // 删掉当前行后需要重新检查这一行
            }
        }
    }

    // 检查当前方块是否能够移动到指定位置，如果能则返回true，否则返回false
    function canMove(piece, x, y) {
        for (let cy = 0; cy < piece.length; cy++){
            for (let cx = 0; cx < piece[cy].length; cx++) {
                if (piece[cy][cx]) {
                    const nx = x + cx;
                    const ny = y + cy;
                    if (ny >= boardHeight || nx < 0 || nx >= boardWidth || board[ny][nx] !== 0) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    // 绘制游戏界面
    function drawBoard() {
        // 清空画布
        context.clearRect(0, 0, canvas.width, canvas.height);

        // 绘制游戏区域中已有的方块
        for (let y = 0; y < board.length; y++) {
            for (let x = 0; x < board[y].length; x++) {
                if (board[y][x] !== 0) {
                    drawBlock(x * blockSize, y * blockSize, pieces[board[y][x] - 1].color);
                }
            }
        }

        // 绘制当前下落的方块
        for (let y = 0; y < currentPiece.length; y++) {
            for (let x = 0; x < currentPiece[y].length; x++) {
                if (currentPiece[y][x]) {
                    drawBlock((pieceX + x) * blockSize, (pieceY + y) * blockSize, pieces[currentPiece[y][x] - 1].color);
                }
            }
        }
    }

    // 在指定位置绘制一个方块
    function drawBlock(x, y, color) {
        context.fillStyle = color;
        context.fillRect(x, y, blockSize, blockSize);
        context.strokeRect(x, y, blockSize, blockSize);
    }

    // 监听按键事件
    document.addEventListener('keydown', event => {
        switch (event.key) {
            case 'ArrowLeft': // 向左移动
                if (canMove(currentPiece, pieceX - 1, pieceY)) {
                    pieceX--;
                }
                break;
            case 'ArrowRight': // 向右移动
                if (canMove(currentPiece, pieceX + 1, pieceY)) {
                    pieceX++;
                }
                break;
            case 'ArrowDown': // 加速下落
                if (canMove(currentPiece, pieceX, pieceY + 1)) {
                    pieceY++;
                }
                break;
            case 'ArrowUp': // 旋转
                rotatePiece();
                break;
        }
    });

    // 将当前方块顺时针旋转90度
    function rotatePiece() {
        let newPiece = [];
        for (let y = 0; y < currentPiece[0].length; y++) {
            let newRow = [];
            for (let x = currentPiece.length - 1; x >= 0; x--) {
                newRow.push(currentPiece[x][y]);
            }
            newPiece.push(newRow);
        }
        if (canMove(newPiece, pieceX, pieceY)) {
            currentPiece = newPiece;
        }
    }
</script>
</body>
</html>